﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using BussinessLogic.Services;
using BussinessLogic.Models;
using Newtonsoft.Json;
using BussinessLogic.Exercise;
using System.Data;
using System.Drawing;

namespace AspMVCProject.Controllers
{
    [Authorize]
    public class SessionController : Controller
    {
        public ActionResult Index(int id)
        {
            return View();
        }

        public ActionResult Daily(int id, bool? initial)
        {
            var session = SessionService.GetNextActivity(id, User.Identity.Name, initial);
            if (session == null)
            {
                return View("NoSession");
            }
            if (session is ActivityProtocolQN)
            {
                return View("Questionnaire", session as ActivityProtocolQN);
            }
            else if (session is ActivityProtocolExercise)
            {
                GenerateExercise(session as ActivityProtocolExercise);
                return View("Exercise", session as ActivityProtocolExercise);
            }
            else if (session is ActivityProtocolMatrix)
            {
                GenerateExerciseMatrix(session as ActivityProtocolMatrix);
                return View("MatrixExercise", session as ActivityProtocolMatrix);
            }
            return View("Error");
        }

        private void GenerateExerciseMatrix(ActivityProtocolMatrix protocol)
        {
            Random random = new Random();

            List<int> negativeIndexes = new List<int>();

            int nIndex = 0;
            protocol.Negatives.ForEach(n => negativeIndexes.Add(nIndex++));

            protocol.Trials = new List<MatrixTrial>(protocol.TrialCount);

            for (int i = 0; i < protocol.TrialCount; i++)
            {
                var trial = new MatrixTrial();
                trial.photos = new List<MatrixPhoto>();
                for (int j = 0; j < 15; j++)
                {
                    if (j % negativeIndexes.Count == 0)
                    {
                        // shuffle
                        negativeIndexes = negativeIndexes.OrderBy(x => Guid.NewGuid()).ToList();
                    }
                    trial.photos.Add(new MatrixPhoto { PhotoIndex = negativeIndexes[j % negativeIndexes.Count], PhotoType = BussinessLogic.PictureType.Negative });
                }
                trial.photos.Insert(random.Next(0, 15), new MatrixPhoto { PhotoIndex = random.Next(0, protocol.Neutrals.Count), PhotoType = BussinessLogic.PictureType.Neutral });

                protocol.Trials.Add(trial);
            }
        }

        [HttpPost]
        public ActionResult Questionnaire(string jsonResult)
        {
            QuestionnaireResult result = JsonConvert.DeserializeObject<QuestionnaireResult>(jsonResult);
            result.UserName = User.Identity.Name;

            SessionService.SaveSessionQn(result);
            if (result.IsForApproval)
            {
                return RedirectToAction("Daily", new { id = result.StudyID, initial = true });
            }
            else
            {
                return RedirectToAction("Daily", new { id = result.StudyID });
            }
        }

        public void GenerateExercise(ActivityProtocolExercise protocol)
        {
            protocol.Trials = new List<ExerciseTrial>();

            List<ExerciseTrial> allCombinations = new List<ExerciseTrial>();

            foreach (var neutralPhoto in protocol.Neutrals)
            {
                foreach (var negativePhoto in protocol.Negatives)
                {
                    foreach (ExerciseTrial.Position neutralPosition in Enum.GetValues(typeof(ExerciseTrial.Position)))
                    {
                        foreach (ExerciseTrial.Position letterPosition in Enum.GetValues(typeof(ExerciseTrial.Position)))
                        {
                            foreach (ExerciseTrial.LetterType letter in Enum.GetValues(typeof(ExerciseTrial.LetterType)))
                            {
                                allCombinations.Add(new ExerciseTrial { NeutralPhoto = neutralPhoto, NegativePhoto = negativePhoto, Letter = letter, LetterPosition = letterPosition, NeutralPosition = neutralPosition });
                            }
                        }
                    }
                }
            }

            foreach (var neutralPhoto in protocol.Neutrals)
            {
                foreach (var neutralPhoto2 in protocol.Neutrals)
                {
                    foreach (ExerciseTrial.Position letterPosition in Enum.GetValues(typeof(ExerciseTrial.Position)))
                    {
                        foreach (ExerciseTrial.LetterType letter in Enum.GetValues(typeof(ExerciseTrial.LetterType)))
                        {
                            allCombinations.Add(new ExerciseTrial { NegativeNeutral = true, NeutralPhoto = neutralPhoto, NegativePhoto = neutralPhoto2, Letter = letter, LetterPosition = letterPosition, NeutralPosition = ExerciseTrial.Position.Up });
                        }
                    }
                }
            }

            //allCombinations.Shuffle();
            allCombinations = allCombinations.OrderBy(a => Guid.NewGuid()).ToList();

            Random randomGenerator = new Random();

            for (int i = 0; i < protocol.AcomodationTrials; i++)
            {
                // add acomodation
                int index = randomGenerator.Next(allCombinations.Count);
                var selectedTrial = allCombinations[index].Clone();
                selectedTrial.SType = ExerciseTrial.SequenceType.Acomodation;
                protocol.Trials.Add(selectedTrial);
            }

            // add baseline
            // basline will not be cloned !
            allCombinations.ForEach((t) => { t.SType = ExerciseTrial.SequenceType.Baseline; protocol.Trials.Add(t); });


            var generateTraining = new List<ExerciseTrial>();
            //add photos for training
            foreach (var trial in protocol.TrainingTrials)
            {
                for (int i = 0; i < trial.Repeat; i++)
                {
                    var fTrial = trial.Clone();
                    fTrial.SType = ExerciseTrial.SequenceType.Final;
                    generateTraining.Add(fTrial);

                    int iNeutral = randomGenerator.Next(protocol.Neutrals.Count);
                    int iNegative = randomGenerator.Next(protocol.Negatives.Count);

                    fTrial.NeutralPhoto = protocol.Neutrals[iNeutral];
                    fTrial.NegativePhoto = protocol.Negatives[iNegative];
                    fTrial.SType = ExerciseTrial.SequenceType.Training;
                }
            }
            generateTraining = generateTraining.OrderBy(a => Guid.NewGuid()).ToList();
            generateTraining.ForEach(t => protocol.Trials.Add(t));

            //final session
            if (protocol.FinalSession)
            {
                //allCombinations.Shuffle();
                allCombinations = allCombinations.OrderBy(a => Guid.NewGuid()).ToList();
                foreach (var trial in allCombinations)
                {
                    var fTrial = trial.Clone();
                    fTrial.SType = ExerciseTrial.SequenceType.Final;
                    protocol.Trials.Add(fTrial);
                }
            }

            //fixation trials

            for (int i = 0; i < protocol.FixationTrial; i++)
            {
                int position = randomGenerator.Next(protocol.AcomodationTrials, protocol.Trials.Count);
                var trial = new ExerciseTrial
                {
                    SType = ExerciseTrial.SequenceType.Fixation,
                    Digit = randomGenerator.Next(1, 4)
                };

                protocol.Trials.Insert(position, trial);
            }

            //protocol.Trials.RemoveRange(5, protocol.Trials.Count - 7);
        }

        [HttpPost]
        public ActionResult Exercise(string jsonResult, int StudyID, ExerciseInfoResult eInfo)
        {
            List<ExerciseTrial> trials = JsonConvert.DeserializeObject<List<ExerciseTrial>>(jsonResult);
            SessionService.SaveSessionExercise(trials, User.Identity.Name, StudyID, eInfo);

            return RedirectToAction("Daily", new { id = StudyID });
        }

        [HttpPost]
        public ActionResult MatrixExercise(string jsonResult,int StudyID, ExerciseInfoResult eInfo)
        {
            var result = JsonConvert.DeserializeObject<List<MatrixTrial>>(jsonResult);
            SessionService.SaveSessionMatrixExercise(result, User.Identity.Name, StudyID, eInfo);

            return RedirectToAction("Daily", new { id = StudyID });
        }

        public ActionResult MatrixExercise()
        {
            ActivityProtocolMatrix protocol = new ActivityProtocolMatrix();

            Random random = new Random();
            protocol.Neutrals = new List<string>()
            {
                "1.png", "2.png", "3.png"
            };

            protocol.Negatives = new List<string>()
            {
                "1.png", "2.png", "3.png", "4.png", "5.png", "6.png", "7.png", "8.png", "9.png"
            };

            List<int> negativeIndexes = new List<int>();

            int nIndex = 0;
            protocol.Negatives.ForEach(n => negativeIndexes.Add(nIndex++));

            protocol.TrialCount = 3;

            protocol.Trials = new List<MatrixTrial>(protocol.TrialCount);

            for (int i = 0; i < protocol.TrialCount; i++)
            {
                var trial = new MatrixTrial();
                trial.photos = new List<MatrixPhoto>();
                for (int j = 0; j < 15; j++)
                {
                    if (j % negativeIndexes.Count == 0)
                    {
                        // shuffle
                        negativeIndexes = negativeIndexes.OrderBy(x => Guid.NewGuid()).ToList();
                    }
                    trial.photos.Add(new MatrixPhoto { PhotoIndex = negativeIndexes[j % negativeIndexes.Count], PhotoType = BussinessLogic.PictureType.Negative });
                }
                trial.photos.Insert(random.Next(0, 15), new MatrixPhoto { PhotoIndex = random.Next(0, protocol.Neutrals.Count), PhotoType = BussinessLogic.PictureType.Neutral });

                protocol.Trials.Add(trial); 
            }

            return View(protocol);
        }

    }
}
